home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v8n07.arc / LASERLST.ASM < prev    next >
Assembly Source File  |  1989-03-13  |  35KB  |  957 lines

  1.         PAGE    75,132
  2.         TITLE   "LASERLST - List file to HP LaserJet"
  3.  
  4. CSEG        SEGMENT PARA PUBLIC 'CODE'
  5.         ASSUME  CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  6.         ORG     100H
  7.  
  8. START:        JMP     MAIN            ; go to start of program
  9.  
  10. HEADER_MSG  DB        "LaserLst 1.0 (c) 1989 Ziff Communications Co.", 0DH,0AH
  11.         DB        "PC Magazine",254," Michael Holmes & Bob Flanders",0DH,0AH
  12. CRLF        DB        0DH,0AH
  13. DOLLAR        DB        "$"
  14. ; ---------------------------------------------------------------------------
  15. ;   Initialized work areas
  16. ; ---------------------------------------------------------------------------
  17. ARG1        DW        0                ; addr of first argument
  18. ARG2        DW        0                ; addr of second argument
  19. PHANDLE     DW        4                ; printer handle (stdprn)
  20. TABCOL        DW        8                ; tab width
  21. NEWPAGE     DB        0                ; new page requested flag
  22. HPSTATE     DB        0                ; printer state  (1 = initialized)
  23.  
  24. TITLE_        DB        1BH,"&dD"               ; title line for heading
  25. TITLE_DTE   DB        "mm/dd/yyyy  "          ; ..and display
  26. TITLE_TME   DB        "hh:mm       Filename: "
  27. TITLE_FLE   DB        19 dup(32)
  28. TITLE_DSP   EQU     $-TITLE_DTE
  29.         DB        "                    Page"
  30. TITLE_PGE   DB        "xxxx",0dh,0ah,0ah
  31.         DB        1BH,"&d@"
  32. TITLE_LEN   EQU     $-TITLE_            ; length of title
  33. ;----------------------------------------------------------------------
  34. ;   DTA structure for DOS "find matching" call
  35. ;----------------------------------------------------------------------
  36. DTA        EQU     80H             ; dta offset
  37. DTA_ATTR    EQU     BYTE PTR DTA+21        ; file attribute
  38. DTA_TIME    EQU     WORD PTR DTA_ATTR+1     ; file time
  39. DTA_DATE    EQU     WORD PTR DTA_TIME+2     ; file date
  40. DTA_LSIZ    EQU     WORD PTR DTA_DATE+2     ; file lsw of size
  41. DTA_HSIZ    EQU     WORD PTR DTA_LSIZ+2     ; file msw of size
  42. DTA_NAME    EQU     BYTE PTR DTA_HSIZ+2     ; file name of file
  43. DTA_LEN     EQU     DTA_NAME+15-DTA        ; length of dta find entry
  44. ;----------------------------------------------------------------------
  45. ;   Messages to user
  46. ;----------------------------------------------------------------------
  47. FILENF        DB        "File not found.",0DH,0AH,"$"
  48. PRTOERR     DB        "Could not open output file.",0DH,0AH,"$"
  49. FORMAT        DB        0DH,0AH,"SYNTAX:",09H,"LASERLST [d:][path]filename[.ext] "
  50.         DB        "[outfile] [/Tn]",0DH, 0AH, 0AH
  51.         DB        "  ofile defaults to LPT1:",0DH,0AH
  52.         DB        "  n is tab width (16 max)",0DH,0AH,"$"
  53. ;----------------------------------------------------------------------
  54. ;   HP control strings
  55. ;----------------------------------------------------------------------
  56. STRING1     DB        1BH,"E",1BH,"&l1O",1BH,"(s17H",1BH,"&l5.14C"
  57.         DB        1BH,"&l71F",1BH,"&l6E",1BH,"(s-3B"
  58.         DB        1BH,"&a0R",1BH,"&a85M",1BH,"&a5L",0DH
  59. STRING1_LEN EQU     $-STRING1
  60.  
  61. STRING2     DB        0ch,1BH,"E"
  62. STRING2_LEN EQU     $-STRING2
  63.  
  64. STRING3     DB        1BH,"&a0R",1BH,"&a90M",1BH,"&a88L",0DH,0AH,0DH,0AH
  65. STRING3_LEN EQU     $-STRING3
  66.  
  67. STRING4     DB        "|", 0DH,0AH
  68.  
  69. STRING5     DB        1BH,"&a0R",1BH,"&a171M",1BH,"&a91L",0DH
  70. STRING5_LEN EQU     $-STRING5
  71.  
  72. STRING6     DB        0CH,1BH,"&a0R",1BH,"&a85M",1BH,"&a5L",0DH
  73. STRING6_LEN EQU     $-STRING6
  74. ; ---------------------------------------------------------------------------
  75. ;   MAIN - Mainline of program
  76. ; ---------------------------------------------------------------------------
  77. MAIN        PROC                ; start of program
  78.  
  79.         CALL    INIT            ; initialize program
  80.  
  81. MAIN10:     CALL    OPEN            ; open the input file
  82.         JC        MAIN80            ; if we can't .. try next
  83.  
  84. MAIN20:     CALL    READ            ; read a block
  85.  
  86.         CALL    PRINT            ; print the line
  87.  
  88.         OR        SI, SI            ; q. end of file?
  89.         JNZ     MAIN20            ; a. no .. get next line
  90.  
  91.         MOV     BX, FHANDLE         ; bx = input file handle
  92.         MOV     AH, 3EH            ; ah = close file
  93.         INT     21H             ; .. ask DOS to do it
  94.  
  95. MAIN80:     MOV     AH, 4FH            ; ah = find next file
  96.         INT     21H             ; q. file found?
  97.         JNC     MAIN10            ; a. yes .. continue
  98.  
  99.         MOV     DX, OFFSET DOLLAR        ; dx -> null message
  100.         CALL    DIE             ; .. say goodnight
  101.  
  102. MAIN        ENDP
  103. ; ---------------------------------------------------------------------------
  104. ;   INIT - Handle initialization
  105. ; ---------------------------------------------------------------------------
  106. INIT        PROC
  107.  
  108.         CLD                 ; assure ascending
  109.         MOV     AH, 19H            ; ah = get current drive
  110.         INT     21H             ; al = current drive
  111.         MOV     EDRV, AL            ; save entry drive
  112.  
  113.         MOV     SI, OFFSET EDIR        ; si -> current directory area
  114.         MOV     BYTE PTR [SI], '\'      ; .. start with backslash
  115.         INC     SI                ; si -> next byte
  116.         XOR     DL, DL            ; dl = default drive
  117.         MOV     AH, 47H            ; ah = get current dir
  118.         INT     21H             ; .. save in area
  119.  
  120.         MOV     DX, OFFSET HEADER_MSG   ; dx -> header message
  121.         MOV     AH, 9            ; ah = print ascii$ message
  122.         INT     21H             ; .. ask DOS to do it
  123.  
  124.         CALL    PARMS            ; check parameters
  125.  
  126.         CMP     ARG2, 0            ; q. arg2 specified?
  127.         JE        INIT20            ; a. yes .. skip open
  128.  
  129.         MOV     DX, ARG2            ; dx -> arg2 value
  130.         MOV     AH, 3CH            ; ah = create file
  131.         XOR     CX, CX            ; .. cx = file attributes
  132.         INT     21H             ; q. open the file ok?
  133.         JNC     INIT10            ; a. yes .. continue
  134.  
  135.         MOV     DX, OFFSET PRTOERR        ; dx -> open error message
  136.         CALL    DIE             ; .. you're dead, Jim.
  137.  
  138. INIT10:     MOV     PHANDLE, AX         ; save printer handle
  139.  
  140. INIT20:     CALL    DFLPATH            ; set up dir & drive
  141.  
  142.         MOV     AH, 4EH            ; ah = find first
  143.         MOV     DX, OFFSET FILENAME     ; dx -> file to find
  144.         XOR     CX, CX            ; cx = search attribute
  145.         INT     21H             ; q. find first file ok?
  146.         JNC     INIT90            ; a. yes .. continue
  147.  
  148.         MOV     DX, OFFSET FILENF        ; dx -> file not found
  149.         CALL    DIE             ; .. gasp you're final breath
  150.  
  151. INIT90:     RET                 ; return to caller
  152.  
  153. INIT        ENDP
  154. ; ---------------------------------------------------------------------------
  155. ;   OPEN - Opens the next file to process and update title line
  156. ;     Exit: Carry indicates file would not open.
  157. ; ---------------------------------------------------------------------------
  158. OPEN        PROC
  159.  
  160.         MOV     DX, OFFSET DTA_NAME     ; dx -> file name
  161.         MOV     AX, 3D00H            ; al = open for read
  162.         INT     21H             ; .. ask DOS to do it.
  163.         JNC     OPEN05            ; ok .. continue
  164.  
  165.         RET                 ; else .. return if error
  166.  
  167. OPEN05:     MOV     FHANDLE, AX         ; save file handle
  168.         MOV     LASTBUFF, 0         ; show last buffer not read
  169.  
  170.         MOV     SI, OFFSET DTA_NAME     ; si -> file name
  171.         MOV     DI, OFFSET TITLE_FLE    ; di -> file name area
  172.         PUSH    DI                ; .. save it
  173.         MOV     AL, ' '                 ; al = blank
  174.         MOV     CX, 15            ; .. amount to blank
  175.       REP   STOSB                ; .. clear the file name
  176.         POP     DI                ; .. restore output pointer
  177.  
  178. OPEN10:     LODSB                ; al = byte from file name
  179.  
  180.         OR        AL, AL            ; q. end of name?
  181.         JZ        OPEN20            ; a. yes .. end loop
  182.  
  183.         STOSB                ; store a byte
  184.         JMP     OPEN10            ; .. and move next
  185.  
  186. OPEN20:     MOV     BL, '0'                 ; fill value
  187.         MOV     AX, DS:DTA_DATE        ; ax = date field
  188.         PUSH    AX                ; save for later
  189.         PUSH    AX                ; .. again
  190.  
  191.         MOV     CL, 5            ; cl = shift value
  192.         SHR     AX, CL            ; .. mm to lower bits
  193.         AND     AX, 0FH            ; .. upper bits off
  194.         MOV     CX, 2            ; cx = number of characters
  195.         MOV     DI, OFFSET TITLE_DTE    ; di -> mm
  196.         CALL    ITOA            ; .. move in mm
  197.  
  198.         POP     AX                ; ax = date
  199.         AND     AX, 1FH            ; al = dd
  200.         MOV     CX, 2            ; cx = number of chars
  201.         MOV     DI, OFFSET TITLE_DTE+3  ; di -> dd
  202.         CALL    ITOA            ; .. move into dd
  203.  
  204.         POP     AX                ; ax = date
  205.         MOV     CL, 9            ; cl = shift amount
  206.         SHR     AX, CL            ; .. ax = yy
  207.         ADD     AX, 1980            ; ax = year
  208.         MOV     CX, 4            ; cx = length of output
  209.         MOV     DI, OFFSET TITLE_DTE+6  ; di -> yyyy
  210.         CALL    ITOA            ; .. move into yyyy
  211.  
  212.         MOV     AX, DS:DTA_TIME        ; ax = time
  213.         PUSH    AX                ; .. save for later
  214.         MOV     CL, 11            ; cl = shift value
  215.         SHR     AX, CL            ; .. ax = hh
  216.         MOV     CX, 2            ; cx = length of output
  217.         MOV     DI, OFFSET TITLE_TME    ; di -> hh
  218.         CALL    ITOA            ; .. move into hh
  219.  
  220.         POP     AX                ; ax = time
  221.         MOV     CL, 5            ; cl = shift value
  222.         SHR     AX, CL            ; ax = mm
  223.         AND     AX, 3FH            ; .. upper bits off
  224.         MOV     CX, 2            ; cx = length of output
  225.         MOV     DI, OFFSET TITLE_TME+3  ; di -> mm
  226.         CALL    ITOA            ; .. move into mm
  227.  
  228.         MOV     AH, 40H            ; ah = write to device
  229.         MOV     BX, 1            ; bx = stdout device
  230.         MOV     CX, TITLE_DSP        ; cx = length to display
  231.         MOV     DX, OFFSET TITLE_DTE    ; dx -> part of header line
  232.         INT     21H             ; issue dos call
  233.  
  234.         MOV     AH, 40H            ; ah = write to device
  235.         MOV     BX, 1            ; bx = stdout device
  236.         MOV     CX, 2            ; cx = length to display
  237.         MOV     DX, OFFSET CRLF        ; dx -> <cr><lf> string
  238.         INT     21H             ; issue dos call
  239.  
  240.         CLC                 ; show all went ok
  241. OPEN90:     RET
  242.  
  243. OPEN        ENDP
  244. ; ---------------------------------------------------------------------------
  245. ;   READ - Read the next buffer full
  246. ;     Exit: si -> next line, 0 if eof, cx =  length of line
  247. ; ---------------------------------------------------------------------------
  248. READ        PROC
  249.  
  250.         PUSH    AX                ; save registers
  251.         PUSH    BX
  252.         PUSH    DX
  253.  
  254.         MOV     SI, 0            ; si -> nothing
  255.  
  256.         CMP     LASTBUFF, 1         ; q. last buffer have 1ah?
  257.         JE        READ90            ; a. yes .. end it all
  258.  
  259.         MOV     AH, 03FH            ; ah = read file
  260.         MOV     BX, FHANDLE         ; bx = handle of file to read
  261.         MOV     CX, BUFLEN            ; cx = amount to read
  262.         MOV     DX, OFFSET BUFFER        ; dx -> buffer
  263.         INT     21H             ; read, please
  264.         JC        READ90            ; error .. return eof
  265.  
  266.         OR        AX, AX            ; q. any read?
  267.         JZ        READ90            ; a. yes .. return with something
  268.  
  269.         MOV     SI, OFFSET BUFFER        ; si -> start of line
  270.         MOV     CX, AX            ; cx = nbr of characters read
  271.         MOV     BX, AX            ; .. and bx
  272.  
  273.         MOV     DI, SI            ; di -> chars read
  274.         MOV     AL, 1AH            ; al = EOF indicator
  275.  
  276.     REPNE   SCASB                ; q. eof found?
  277.         JNE     READ80            ; a. no .. continue
  278.  
  279.         INC     CX                ; .. increment count
  280.         NEG     CX                ; .. and negate it
  281.         MOV     LASTBUFF, 1         ; .. and set lastbuff flag
  282.  
  283. READ80:     ADD     CX, BX            ; q. any bytes this buffer?
  284.         JNZ     READ90            ; a. yes .. continue
  285.  
  286.         MOV     SI, 0            ; a. else .. show end of file.
  287.  
  288. READ90:     POP     DX                ; restore registers
  289.         POP     BX                ;
  290.         POP     AX                ;
  291.         RET                 ; ..and return to caller
  292.  
  293. READ        ENDP
  294. ; ---------------------------------------------------------------------------
  295. ;   PRINT - Print requested data
  296. ;     Entry: si -> string to print or 0, cx =  length of input string
  297. ; ---------------------------------------------------------------------------
  298. PRINT        PROC
  299.  
  300.         OR        SI, SI            ; q. end of file call?
  301.         JNE     PRINT10            ; a. no .. continue
  302.  
  303.         CALL    EPILOGUE            ; put out trailing characters
  304.         RET                 ; ..and return to caller
  305.  
  306. PRINT10:    PUSH    AX                ; save registers
  307.         PUSH    BX
  308.         PUSH    CX
  309.         PUSH    DX
  310.         PUSH    SI
  311.  
  312.         CMP     HPSTATE, 0            ; q. initial state?
  313.         JNE     PRINT20            ; a. no .. continue
  314.  
  315.         CALL    PROLOGUE            ; send out initial string
  316.  
  317. PRINT20:    CALL    EXPAND            ; handle tab expansion
  318.         MOV     DX, SI            ; dx -> start of new buffer
  319.         MOV     BX, CX            ; bx = nbr of chars in buffer
  320.         XOR     CX, CX            ; cx = nbr of chars to print
  321.         MOV     AH, USEDLEN         ; ah = printed chars in this line
  322.  
  323. PRINT30:    LODSB                ; al = first character
  324.  
  325.         CMP     AL, 0CH            ; q. formfeed?
  326.         JNE     PRINT40            ; a. yes .. process it
  327.  
  328.         CALL    LINEPRT            ; print the line
  329.         CALL    PAGEBREAK            ; do a page break
  330.         XOR     AH, AH            ; ah = nbr of columns used
  331.         DEC     BX                ; bx = decrement remaining count
  332.         INC     DX                ; dx -> next printable character
  333.         JMP     PRINT70            ; ..and continue w/common code
  334.  
  335. PRINT40:    CMP     AL, 0AH            ; q. linefeed?
  336.         JNE     PRINT50            ; a. no .. continue
  337.  
  338.         DEC     BX                ; bx = remaining chars in buffer
  339.         INC     CX                ; cx = nbr of characters to print
  340.         CALL    LINEPRT            ; print the line
  341.         XOR     AH, AH            ; ah = nbr of columns used
  342.         CALL    BUMPLINE            ; increment/test line counter
  343.         JMP     PRINT70            ; ..and continue w/common code
  344.  
  345. PRINT50:    CMP     AL, 0DH            ; q. carriage return?
  346.         JNE     PRINT55            ; a. no .. continue
  347.         JMP     SHORT PRINT57        ; ..and continue w/common code
  348.  
  349. PRINT55:    CMP     AL, 08H            ; q. BackSpace?
  350.         JNE     PRINT60            ; a. no .. continue
  351.  
  352.         DEC     AH                ; move back a column
  353.         JNS     PRINT65            ; .. but not beyond first
  354.  
  355. PRINT57:    XOR     AH, AH            ; ah = start of line
  356.         JMP     SHORT PRINT65        ; .. and continue
  357.  
  358. PRINT60:    INC     AH                ; increment nbr of columns used
  359. PRINT65:    INC     CX                ; ..and nbr of chars to print
  360.         DEC     BX                ; decrement remaining char count
  361.  
  362.         CMP     AH, 81            ; q. reached end of line?
  363.         JL        PRINT70            ; a. no .. continue
  364.  
  365.         CALL    LINEPRT            ; print upto page width
  366.         PUSH    CX                ; save registers
  367.         PUSH    DX                ;
  368.         MOV     DX, OFFSET CRLF        ; dx -> <cr><lf>
  369.         MOV     CX, 2            ; cx = string length
  370.         CALL    WRITE            ; print the crlf to do line wrapping
  371.         POP     DX                ; restore registers
  372.         POP     CX                ;
  373.         XOR     AH, AH            ; ah = nbr of columns used
  374.         CALL    BUMPLINE            ; increment/test line counter
  375.  
  376. PRINT70:    OR        BX, BX            ; q. anything left to check?
  377.         JNZ     PRINT30            ; a. yes .. loop till done
  378.  
  379.         CALL    LINEPRT            ; print the line
  380.         MOV     USEDLEN, AH         ; save nbr of columns used
  381.  
  382.         POP     SI                ; restore registers
  383.         POP     DX                ;
  384.         POP     CX                ;
  385.         POP     BX                ;
  386.         POP     AX                ;
  387.         RET                 ; ..and return to caller
  388.  
  389. PRINT        ENDP
  390. ; ---------------------------------------------------------------------------
  391. ;   DIE - Display an error message and return to DOS
  392. ;     Entry: dx -> error message ended in dollar sign.
  393. ; ---------------------------------------------------------------------------
  394. DIE        PROC
  395.  
  396.         MOV     AH, 9            ; ah = print string
  397.         INT     21H             ; .. call dos to print error
  398.  
  399.         MOV     DL, EDRV            ; dl = drive to select
  400.         MOV     AH, 0EH            ; ah = select drive
  401.         INT     21H             ; .. select the drive
  402.  
  403.         MOV     DX, OFFSET EDIR        ; dx -> directory
  404.         MOV     AH, 3BH            ; ah = CHDIR request
  405.         INT     21H             ; .. ask DOS to do it
  406.  
  407.         MOV     AX, 4C00H            ; ax = exit
  408.         INT     21H             ; .. terminate routine
  409.  
  410. DIE        ENDP
  411. ; ---------------------------------------------------------------------------
  412. ;   PARMS - Parses the command line
  413. ; ---------------------------------------------------------------------------
  414. PARMS        PROC
  415.  
  416.         CALL    UPCASE            ; upper case the parm area
  417.         MOV     SI, 81H            ; si -> parms area
  418.  
  419. PARMS10:    LODSB                ; get parameter character
  420.  
  421.         CMP     AL, '/'                 ; q. option?
  422.         JE        PARMS80            ; a. yes .. check option
  423.         CMP     AL, 0DH            ; q. end of line?
  424.         JE        PARMS50            ; a. yes .. exit
  425.         CMP     AL, ' '                 ; q. blank?
  426.         JNA     PARMS10            ; a. yes .. skip
  427.         CALL    ARG             ; set the argument
  428.         JC        PARMSERR            ; .. die on an error
  429.  
  430. PARMS30:    LODSB                ; get next character
  431.         CMP     AL, 0DH            ; q. end of line?
  432.         JE        PARMS50            ; a. yes .. process
  433.         CMP     AL, '/'                 ; q. start of option?
  434.         JE        PARMS80            ; a. yes .. process
  435.         CMP     AL, ' '                 ; q. end of PARMS?
  436.         JA        PARMS30            ; a. no .. next char
  437.  
  438.         CALL    ENDPARM            ; terminate parm string
  439.         JMP     PARMS10            ; .. look for next
  440.  
  441. PARMS50:    CALL    ENDPARM            ; terminate parm string
  442.  
  443.         CMP     ARG1, 0            ; q. PARMS 1 available?
  444.         JE        PARMSERR            ; a. no .. error
  445.         RET                 ; .. else .. return to caller
  446.  
  447. PARMS80:    CALL    ENDPARM            ; terminate parm string
  448.         LODSB                ; al = option character
  449.  
  450.         CMP     AL, 'T'                 ; q. Tab width?
  451.         JNE     PARMSERR            ; a. no .. error in option
  452.  
  453.         CALL    ATOI            ; ax =  tab width
  454.  
  455.         CMP     AX, 16            ; q. request greater than max?
  456.         JG        PARMS10            ; a. yes .. unreasonable
  457.  
  458.         MOV     TABCOL, AX            ; .. save tab width
  459.         JMP     PARMS10            ; .. continue scan
  460.  
  461. PARMSERR:   MOV     DX, OFFSET FORMAT        ; dx -> format message
  462.         CALL    DIE             ; abort
  463.  
  464. PARMS        ENDP
  465. ; ---------------------------------------------------------------------------
  466. ;   ARG - Setup pointers to the command line arguments
  467. ;     Entry: si -> second character in argument.
  468. ;     Exit: ARG1 or ARG2 pointers filled in.
  469. ;    Carry set if more than 2 arguments detected.
  470. ; ---------------------------------------------------------------------------
  471. ARG        PROC
  472.  
  473.         LEA     BX, [SI-1]            ; bx -> argument
  474.         CMP     ARG1, 0            ; q. arg1 filled in?
  475.         JNE     ARG10            ; a. yes .. check 2
  476.         MOV     ARG1, BX            ; save arg1 pointer
  477.         JMP     SHORT ARG90         ; .. exit ok!
  478.  
  479. ARG10:        CMP     ARG2, 0            ; q. arg2 filled in?
  480.         JE        ARG20            ; a. no .. fill it in
  481.         STC                 ; else .. error
  482.         RET                 ; .. and return to caller
  483.  
  484. ARG20:        MOV     ARG2, BX            ; save arg2 pointer
  485. ARG90:        CLC                 ; show no error
  486.         RET                 ; return to caller
  487.  
  488. ARG        ENDP
  489. ; ---------------------------------------------------------------------------
  490. ;   ENDPARM - Handle parameters which end in a colon
  491. ;     Entry: si -> first character past end of parameter
  492. ; ---------------------------------------------------------------------------
  493. ENDPARM     PROC
  494.  
  495.         CMP     BYTE PTR [SI-2], ':'    ; q. argument end in a colon?
  496.         JNE     ENDPARM10            ; a. no .. continue
  497.  
  498.         MOV     BYTE PTR [SI-2], 0        ; ..it doesn't any more
  499.         RET                 ; ..and return
  500.  
  501. ENDPARM10:  MOV     BYTE PTR [SI-1], 0        ; end the parameter
  502.         RET                 ; ..and return
  503.  
  504. ENDPARM     ENDP
  505. ; ---------------------------------------------------------------------------
  506. ;   DFLPATH - Setup the default drive and path
  507. ; ---------------------------------------------------------------------------
  508. DFLPATH     PROC
  509.  
  510.         MOV     DI, ARG1            ; di -> first arg
  511.  
  512. DFLPATH10:  CMP     BYTE PTR [DI+1], ':'    ; q. drive specified?
  513.         JNE     DFLPATH20            ; a. no .. use current drive
  514.         MOV     DL, [DI]            ; dl = drive to use
  515.         SUB     DL, 'A'                 ; get requested drive number
  516.         MOV     AH, 0EH            ; set requested drive
  517.         INT     21H             ; .. via dos
  518.         ADD     DI, 2            ; di -> next part
  519.  
  520. DFLPATH20:  PUSH    DI                ; save pointer
  521.         MOV     BX, DI            ; bx -> start of area
  522.         XOR     AL, AL            ; al = search for null
  523.         MOV     CX, 128            ; very max to search
  524.         CLD
  525.     REPNE   SCASB                ; find end of arg
  526.         LEA     SI, [DI-1]            ; si -> nul
  527.         MOV     CX, 0            ; cx = # chars to move
  528.         CMP     SI, BX            ; q. any file name
  529.         JE        DFLPATH80            ; a. no .. error
  530.  
  531. DFLPATH30:  DEC     SI                ; si -> prev char
  532.         CMP     BYTE PTR [SI], '\'      ; q. dir?
  533.         JE        DFLPATH35            ; a. yes .. end of file name.
  534.         INC     CX                ; cx = char count
  535.         CMP     SI, BX            ; q. done?
  536.         JE        DFLPATH37            ; a. yes .. move file name
  537.         JMP     DFLPATH30            ; .. continue
  538.  
  539. DFLPATH35:  INC     SI                ; si -> start of file name
  540. DFLPATH37:  OR        CX, CX            ; q. file name spec'd?
  541.         JZ        DFLPATH80            ; a. no .. error
  542.         CMP     CX, 12            ; q. too long?
  543.         JA        DFLPATH85            ; a. yes .. error
  544.         PUSH    SI                ; save start pointer
  545.         MOV     DI, OFFSET FILENAME     ; di -> file name
  546.         INC     CX                ; .. assure nul moves too
  547.      REP    MOVSB                ; .. move in the file name
  548.         POP     SI                ; restore start pointer
  549.         POP     DI                ; .. and dir pointer
  550.         CMP     SI, BX            ; q. at start of parm?
  551.         JE        DFLPATH90            ; a. yes .. return
  552.         INC     BX                ; bx -> next char
  553.         CMP     SI, BX            ; q. root only given?
  554.         JE        DFLPATH40            ; a. yes .. continue
  555.         DEC     SI                ; si -> last \
  556.  
  557. DFLPATH40:  MOV     BYTE PTR [SI], 0        ; make dir ASCIIZ
  558. DFLPATH50:  MOV     DX, DI            ; dx -> directory
  559.         MOV     AH, 3BH            ; ah = CHDIR opcode
  560.         INT     21H             ; .. change directory
  561.         JNC     DFLPATH90            ; if ok .. continue
  562.         JMP     SHORT DFLPATH85        ; dx -> baddir request
  563.  
  564. DFLPATH80:  MOV     DX, OFFSET FORMAT        ; dx -> no file specified
  565.         CALL    DIE
  566.  
  567. DFLPATH85:  MOV     DX, OFFSET FILENF        ; dx -> invalid filename spec'd
  568.         CALL    DIE
  569.  
  570. DFLPATH90:  RET                 ; return to caller
  571.  
  572. DFLPATH     ENDP
  573. ; ---------------------------------------------------------------------------
  574. ;   EXPAND - Handle tab expansion
  575. ;     Entry:
  576. ;    si -> line read from file ended by a linefeed
  577. ;    cx =  length of line
  578. ;     Exit:
  579. ;    si -> reformatted line in output buffer
  580. ;    cx =  new line length
  581. ; ---------------------------------------------------------------------------
  582. EXPAND        PROC
  583.  
  584.         PUSH    AX                ; save registers
  585.         PUSH    BX
  586.         PUSH    DX
  587.         PUSH    DI
  588.  
  589.         MOV     DI, OFFSET OBUFF        ; di -> start of output buffer
  590.  
  591. EXPAND10:   LODSB                ; al = character from input line
  592.  
  593.         CMP     AL, 09H            ; q. tab character?
  594.         JNE     EXPAND30            ; a. no .. continue processing
  595.  
  596.         MOV     AX, CURCOL            ; ax = current column
  597.         DEC     AX                ; ax = column offset
  598.         XOR     DX, DX            ; dx:ax = current column
  599.         MOV     BX, TABCOL            ; bx = nbr of columns per tab
  600.         IDIV    BX                ; dx = space within tab stop
  601.  
  602.         SUB     BX, DX            ; bx = spaces left in tab stop
  603.  
  604.         MOV     AL, 20H            ; al = space char to padding string
  605.  
  606. EXPAND20:   STOSB                ; put a blank in output buffer
  607.         INC     CURCOL            ; bump current column nbr
  608.  
  609.         DEC     BX                ; q. done yet?
  610.         JNZ     EXPAND20            ; a. no .. keep looping
  611.         JMP     SHORT EXPAND50        ; a. yes .. get next character
  612.  
  613. EXPAND30:   CMP     AL, 0DH            ; q. carriage return?
  614.         JE        EXPAND33            ; a. yes .. reset column
  615.  
  616.         CMP     AL, 0CH            ; q. form feed?
  617.         JNE     EXPAND35            ; a. no .. continue processing
  618.  
  619. EXPAND33:   MOV     CURCOL, 0            ; setup for start of new line
  620.         JMP     SHORT EXPAND40        ; .. continue
  621.  
  622. EXPAND35:   CMP     AL, 08H            ; q. backspace?
  623.         JNE     EXPAND40            ; a. no .. continue
  624.  
  625.         STOSB                ; save the BS
  626.         DEC     CURCOL            ; .. move back a space
  627.         JNZ     EXPAND50            ; .. get next character
  628.  
  629.         MOV     CURCOL, 1            ; init current column
  630.         JMP     SHORT EXPAND50        ; .. continue
  631.  
  632. EXPAND40:   STOSB                ; move character to output line
  633.         CMP     AL, 0AH            ; q. line feed?
  634.         JE        EXPAND50            ; a. yes .. don't count it
  635.  
  636.         INC     CURCOL            ; bump current column nbr
  637.  
  638. EXPAND50:   LOOP    EXPAND10            ; ..loop till input exhausted
  639.  
  640.         MOV     SI, OFFSET OBUFF        ; si -> start of output buffer
  641.         MOV     CX, DI            ; di -> just past last char of output
  642.         SUB     CX, SI            ; cx = nbr of characters in output
  643.  
  644.         POP     DI                ; restore registers
  645.         POP     DX
  646.         POP     BX
  647.         POP     AX
  648.         RET                 ; ..and return to caller
  649.  
  650. EXPAND        ENDP
  651. ; ---------------------------------------------------------------------------
  652. ;   LINEPRT - Handle printing a line
  653. ;     Entry:
  654. ;    dx -> start of line
  655. ;    cx =  nbr of characters to print
  656. ;     Exit:
  657. ;    dx -> start of next line
  658. ;    cx =  0
  659. ; ---------------------------------------------------------------------------
  660. LINEPRT     PROC
  661.  
  662.         JCXZ    LINEPRT90            ; if nothing to print.. return
  663.  
  664.         CMP     NEWPAGE, 1            ; q. need a new page?
  665.         JNE     LINEPRT10            ; a. no .. continue
  666.  
  667.         CALL    PAGEBREAK            ; else .. do a pagebreak
  668.  
  669. LINEPRT10:  CALL    WRITE            ; write the line
  670.  
  671.         ADD     DX, CX            ; dx -> start of next line
  672.         XOR     CX, CX            ; cx = nbr of characters to print
  673. LINEPRT90:  RET
  674.  
  675. LINEPRT     ENDP
  676. ; ---------------------------------------------------------------------------
  677. ;   MKTITLE - Make the title line be ready to print
  678. ;     Exit:
  679. ;    dx -> title line
  680. ;    cx =  title line length
  681. ; ---------------------------------------------------------------------------
  682. MKTITLE     PROC
  683.         PUSH    AX                ; save registers
  684.         PUSH    BX
  685.         PUSH    DI
  686.  
  687.         MOV     AX, PAGENO            ; ax = page number
  688.         MOV     CX, 4            ; cx = length of output
  689.         MOV     BL, ' '                 ; bl = fill char (blank)
  690.         MOV     DI, OFFSET TITLE_PGE    ; di -> output area
  691.         CALL    ITOA            ; .. fill in page number
  692.  
  693.         MOV     DX, OFFSET TITLE_        ; dx -> title
  694.         MOV     CX, TITLE_LEN        ; cx = length of title
  695.         CALL    WRITE            ; print title line
  696.  
  697.         POP     DI                ; restore registers
  698.         POP     BX
  699.         POP     AX
  700.         RET                 ; return to caller
  701.  
  702. MKTITLE     ENDP
  703. ; ---------------------------------------------------------------------------
  704. ;   PAGEBREAK - Handle page overflow condition
  705. ; ---------------------------------------------------------------------------
  706. PAGEBREAK   PROC
  707.  
  708.         PUSH    BX                ; save registers
  709.         PUSH    CX
  710.         PUSH    DX
  711.  
  712.         TEST    PAGENO, 1            ; q. finishing up with left page?
  713.         JZ        PAGEBRK20            ; a. no .. do other page
  714.  
  715.         MOV     DX, OFFSET STRING3        ; dx -> get to right page string
  716.         MOV     CX, STRING3_LEN        ; cx = length
  717.         CALL    WRITE            ; write out 1st part of string
  718.  
  719.         MOV     BX, 66            ; bx = loop count
  720.         MOV     CX, 3            ; cx = nbr of chars to print
  721.         MOV     DX, OFFSET STRING4        ; dx -> vertical bar string
  722.  
  723. PAGEBRK10:  CALL    WRITE            ; write on line of vertical bars
  724.  
  725.         DEC     BX                ; q. done yet?
  726.         JNZ     PAGEBRK10            ; a. no .. keep looping
  727.  
  728.         MOV     DX, OFFSET STRING5        ; dx -> string to finish up
  729.         MOV     CX, STRING5_LEN        ; cx = length
  730.         JMP     PAGEBRK30            ; ..and continue w/common code
  731.  
  732. PAGEBRK20:  MOV     DX, OFFSET STRING6        ; dx -> get to left page string
  733.         MOV     CX, STRING6_LEN        ; cx = length
  734.  
  735. PAGEBRK30:  CALL    WRITE            ; print the init line
  736.  
  737.         MOV     LINECNT, 1            ; reset line counter
  738.         MOV     NEWPAGE, 0            ; clear new page request flag
  739.         INC     PAGENO            ; ..and bump page number
  740.  
  741.         CALL    MKTITLE            ; print title line
  742.  
  743.         POP     DX                ; restore registers
  744.         POP     CX                ;
  745.         POP     BX                ;
  746.         RET                 ; ..and return to caller
  747.  
  748. PAGEBREAK   ENDP
  749. ; ---------------------------------------------------------------------------
  750. ;   BUMPLINE - Increment line counter and test for overflow
  751. ; ---------------------------------------------------------------------------
  752. BUMPLINE    PROC
  753.         INC     LINECNT            ; increment line counter
  754.  
  755.         CMP     LINECNT, 66         ; q. reached max lines/page?
  756.         JLE     BUMPLINE90            ; a. no .. continue
  757.  
  758.         MOV     NEWPAGE, 1            ; else .. show we'll need a new one
  759.  
  760. BUMPLINE90: RET                 ; ..then return to caller
  761.  
  762. BUMPLINE    ENDP
  763. ; ---------------------------------------------------------------------------
  764. ;   PROLOGUE - Put out laserjet initialization string
  765. ; ---------------------------------------------------------------------------
  766. PROLOGUE    PROC
  767.  
  768.         PUSH    CX                ; save registers
  769.         PUSH    DX
  770.  
  771.         MOV     DX, OFFSET STRING1        ; dx -> initialization string
  772.         MOV     CX, STRING1_LEN        ; cx = length
  773.         CALL    WRITE            ; print the init line
  774.  
  775.         MOV     PAGENO, 1            ; setup page number
  776.         MOV     CURCOL, 1            ; ..and current column number
  777.         MOV     LINECNT, 1            ; ..and line counter
  778.         MOV     HPSTATE, 1            ; ..show in left page
  779.         MOV     USEDLEN, 0            ; ..clear column position
  780.         CALL    MKTITLE            ; print title line
  781.  
  782.         POP     DX                ; restore registers
  783.         POP     CX                ;
  784.         RET                 ; ..and return to caller
  785.  
  786. PROLOGUE    ENDP
  787. ; ---------------------------------------------------------------------------
  788. ;   EPILOGUE - Put out laserjet finish up string
  789. ; ---------------------------------------------------------------------------
  790. EPILOGUE    PROC
  791.  
  792.         PUSH    CX                ; save registers
  793.         PUSH    DX
  794.  
  795.         MOV     DX, OFFSET STRING2        ; dx -> termination string
  796.         MOV     CX, STRING2_LEN        ; cx = length
  797.         CALL    WRITE            ; print the init line
  798.  
  799.         MOV     HPSTATE, 0            ; show back to initialization state
  800.  
  801.         POP     DX                ; restore registers
  802.         POP     CX                ;
  803.         RET                 ; ..and return to caller
  804.  
  805. EPILOGUE    ENDP
  806. ; ---------------------------------------------------------------------------
  807. ;   WRITE - Send a string to the printer
  808. ;     Entry:
  809. ;    dx -> string to write
  810. ;    cx =  nbr of characters
  811. ; ---------------------------------------------------------------------------
  812. WRITE        PROC
  813.  
  814.         PUSH    AX                ; save registers
  815.         PUSH    BX
  816.  
  817.         MOV     AH, 40H            ; ah = write to file/device function
  818.         MOV     BX, PHANDLE         ; bx = printer handle
  819.         INT     21H             ; issue dos call
  820.  
  821.         POP     BX                ; restore registers
  822.         POP     AX                ;
  823.         RET                 ; ..and return to caller
  824.  
  825. WRITE        ENDP
  826. ; ---------------------------------------------------------------------------
  827. ;   UPCASE - Convert command line arguments to uppercase
  828. ; ---------------------------------------------------------------------------
  829. UPCASE        PROC
  830.  
  831.         PUSH    SI                ; save caller regs
  832.         PUSH    DI
  833.         MOV     SI, 81H            ; si -> start of parm area
  834.         MOV     DI, SI            ; .. same for di
  835.         CLD                 ; .. assure ascending
  836.  
  837. UPCASE10:   LODSB                ; al = char
  838.         CMP     AL, 0DH            ; q. end of line?
  839.         JE        UPCASE90            ; a. yes .. end of line!
  840.         CMP     AL, 'a'                 ; q. is it below 'a'?
  841.         JB        UPCASE20            ; a. yes .. continue
  842.         CMP     AL, 'z'                 ; q. is it above 'z'?
  843.         JA        UPCASE20            ; a. yes .. continue
  844.         SUB     AL, 20H            ; set to upper case
  845.  
  846. UPCASE20:   STOSB                ; save the byte
  847.         JMP     UPCASE10            ; .. and continue
  848.  
  849. UPCASE90:   POP     DI                ; restore caller regs
  850.         POP     SI
  851.         RET                 ; .. and return to caller
  852.  
  853. UPCASE        ENDP
  854. ; ---------------------------------------------------------------------------
  855. ;   ATOI - Translate an ascii value to binary
  856. ;     Entry:
  857. ;    si -> ascii value
  858. ;     Exit:
  859. ;    al =  binary value
  860. ; ---------------------------------------------------------------------------
  861. ATOI        PROC
  862.  
  863.         XOR     AX, AX            ; ax = accumulator = 0
  864.  
  865. ATOI10:     CMP     BYTE PTR [SI], '0'      ; q. below ascii 0?
  866.         JB        ATOI90            ; a. yes.. exit
  867.  
  868.         CMP     BYTE PTR [SI], '9'      ; q. above ascii 9?
  869.         JA        ATOI90            ; a. yes.. exit
  870.  
  871.         XOR     AH, AH            ; reset ah
  872.         MOV     BL, 10            ; bl = multiply value
  873.         MUL     BL                ; .. multiply by 10
  874.         MOV     BL, [SI]            ; bl = value
  875.         AND     BL, 0FH            ; .. upper bits off
  876.         ADD     AL, BL            ; .. add to bl
  877.  
  878.         INC     SI                ; si -> next char
  879.         JMP     ATOI10            ; .. tranlate it
  880.  
  881. ATOI90:     RET                 ; .. return to caller
  882.  
  883. ATOI        ENDP
  884. ; ---------------------------------------------------------------------------
  885. ;   ITOA - Integer to ASCII characters
  886. ;     Entry:
  887. ;    ax =  value to convert
  888. ;    bl =  fill character
  889. ;    cx =  nbr of characters
  890. ;    di -> start of alpha area
  891. ; ---------------------------------------------------------------------------
  892. ITOA        PROC
  893.  
  894.         PUSH    AX                ; save registers
  895.         PUSH    BX
  896.         PUSH    CX
  897.         PUSH    DX
  898.         PUSH    DI
  899.         PUSHF
  900.         STD                 ; ..and set direction flag
  901.  
  902.         ADD     DI, CX            ; di -> 1st char past work area
  903.         DEC     DI                ; di -> last char in work area
  904.         PUSH    BX                ; save fill character
  905.         MOV     BX, 10            ; bx = divisor
  906.  
  907. ITOA10:     OR        AX, AX            ; q. any value to convert?
  908.         JZ        ITOA20            ; a. no .. exit loop
  909.  
  910.         XOR     DX, DX            ; dx:ax = value to divide
  911.         IDIV    BX                ; ax = dividend, dx = remainder
  912.         OR        DL, 30H            ; dl = ASCII number
  913.         MOV     [DI], DL            ; store character in buffer
  914.         DEC     DI                ; di -> next output char location
  915.  
  916.         DEC     CX                ; q. any more room in buffer?
  917.         JNZ     ITOA10            ; a. yes .. continue loop
  918.  
  919.         POP     BX                ; restore register
  920.         JMP     ITOA90            ; ..and exit through common code
  921.  
  922. ITOA20:     POP     AX                ; al = fill character
  923.  
  924. ITOA30:     STOSB                ; store fill character
  925.  
  926.         DEC     CX                ; q. any more room in buffer?
  927.         JNZ     ITOA30            ; a. yes .. continue loop
  928.  
  929. ITOA90:     POPF                ; restore flags
  930.         POP     DI                ; ..and registers
  931.         POP     DX                ;
  932.         POP     CX                ;
  933.         POP     BX                ;
  934.         POP     AX                ;
  935.         RET                 ; ..and return
  936.  
  937. ITOA        ENDP
  938. ; ---------------------------------------------------------------------------
  939. ;   Uninitialized data areas
  940. ; ---------------------------------------------------------------------------
  941. UDATA        EQU     $                ; start of unitialized data
  942. PAGENO        EQU     WORD PTR UDATA        ; current page number
  943. CURCOL        EQU     WORD PTR PAGENO+2        ; current column
  944. LINECNT     EQU     WORD PTR CURCOL+2        ; line count
  945. EDRV        EQU     BYTE PTR LINECNT+2        ; current disk
  946. EDIR        EQU     BYTE PTR EDRV+1        ; current directory
  947. FILENAME    EQU     BYTE PTR EDIR+65        ; filename specifed as ARG1
  948. LASTBUFF    EQU     BYTE PTR FILENAME+13    ; last buffer indicator
  949. FHANDLE     EQU     WORD PTR LASTBUFF+1     ; input file handle
  950. BUFFER        EQU     BYTE PTR FHANDLE+2        ; file buffer
  951. BUFLEN        EQU     2048            ; length of buffer
  952. USEDLEN     EQU     BYTE PTR BUFFER+BUFLEN  ; used length in a logical line
  953. OBUFF        EQU     BYTE PTR USEDLEN+1        ; output buffer - must be last!
  954.  
  955. CSEG        ENDS                ; end of code segment
  956.         END     START
  957.